﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using DTO = Microsoft.MSE.Catalog.Contracts;
using System.Xml;

namespace Microsoft.MSE.Catalog.Module.Data
{
    public class Policy 
    {
        public Policy()
        {

        }

        public static Guid CreatePolicy(DTO.Policy policy, SqlTransaction txn, SqlConnection conn)
        {
            Guid ID;
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[CreatePolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@ID", SqlDbType.UniqueIdentifier);
                    SqlParameter NameParam = new SqlParameter("@Name", SqlDbType.NVarChar, 400);
                    SqlParameter EntityTypeIDParam = new SqlParameter("@EntityTypeID", SqlDbType.SmallInt);
                    SqlParameter DescriptionParam = new SqlParameter("@Description", SqlDbType.NText);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Direction = ParameterDirection.Output;
                    NameParam.Value = policy.Name;
                    EntityTypeIDParam.Value = (int)policy.EntityClass;

                    DescriptionParam.Value = policy.Description;

                    cmd.Parameters.Add(IDParam);
                    cmd.Parameters.Add(NameParam);
                    cmd.Parameters.Add(EntityTypeIDParam);
                    cmd.Parameters.Add(DescriptionParam);

                    cmd.ExecuteNonQuery();
                    ID = (Guid)IDParam.Value;
                }
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }


            return ID;
        }

        public static void DeletePolicy(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[DeletePolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@ID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Value = ID;
                    cmd.Parameters.Add(IDParam);

                    cmd.ExecuteNonQuery();
                }

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }
        }

        public static DTO.Policy UpdatePolicy(DTO.Policy policy, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[UpdatePolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@ID", SqlDbType.UniqueIdentifier);
                    SqlParameter NameParam = new SqlParameter("@Name", SqlDbType.NVarChar, 400);
                    SqlParameter EntityTypeIDParam = new SqlParameter("@EntityTypeID", SqlDbType.SmallInt);
                    SqlParameter DescriptionParam = new SqlParameter("@Description", SqlDbType.NText);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Value = policy.ID;
                    NameParam.Value = policy.Name;
                    EntityTypeIDParam.Value = (int)policy.EntityClass;
                    DescriptionParam.Value = policy.Description;

                    cmd.Parameters.Add(IDParam);
                    cmd.Parameters.Add(NameParam);
                    cmd.Parameters.Add(EntityTypeIDParam);
                    cmd.Parameters.Add(DescriptionParam);

                    cmd.ExecuteNonQuery();
                }

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }

            return policy;
        }

        public static DTO.Policy GetPolicy(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            DTO.Policy policy = new DTO.Policy();
            const string sprocname = "[ServiceEngine].[GetPolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@ID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Value = ID;
                    cmd.Parameters.Add(IDParam);

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            reader.Read();
                            policy.ID = reader.GetGuid(0);
                            policy.Name = reader.GetString(1);
                            //policy.EntityClass = (DTO.EntityClass)Enum.ToObject(typeof(DTO.EntityClass), reader.GetInt32(2));
                            policy.EntityClass = (DTO.EntityClass)reader.GetInt16(2);
                            if (reader.IsDBNull(3))
                            {
                                policy.Description = null;
                            }
                            else
                            {
                                policy.Description = reader.GetString(3);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }

            return policy;

        }

        public static DTO.PolicyList ListPolicies(SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            DTO.PolicyList list = new DTO.PolicyList();
            const string sprocname = "[ServiceEngine].[ListPolicies]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            list.Policies = new List<DTO.PolicyListElement>();
                            while (reader.Read())
                            {
                                DTO.PolicyListElement element = new DTO.PolicyListElement();
                                element.ID = reader.GetGuid(0);
                                element.Name = reader.GetString(1);
                                if (reader.IsDBNull(2))
                                {
                                    element.Description = null;
                                }
                                else
                                {
                                    element.Description = reader.GetString(2);
                                }
                                list.Policies.Add(element);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }

            return list;

        }

        public static List<DTO.PolicyListElement> ListPoliciesByGroup(Guid entityGroupID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            List<DTO.PolicyListElement> list = new List<DTO.PolicyListElement>();
            const string sprocname = "[ServiceEngine].[ListEntitiesByGroup]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@entityGroupID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Value = entityGroupID;
                    cmd.Parameters.Add(IDParam);

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            list = new List<DTO.PolicyListElement>();
                            while (reader.Read())
                            {
                                DTO.PolicyListElement element = new DTO.PolicyListElement();
                                element.ID = reader.GetGuid(0);
                                element.Name = reader.GetString(1);
                                if (reader.IsDBNull(2))
                                {
                                    element.Description = null;
                                }
                                else
                                {
                                    element.Description = reader.GetString(2);
                                }

                                list.Add(element);
                            }
                        }
                    }
                }

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }
            return list;

        }

        public static DTO.PolicyList ListPoliciesForPolicyAssertionID(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            DTO.PolicyList list = new DTO.PolicyList();
            const string sprocname = "[ServiceEngine].[ListPoliciesForPolicyAssertionID]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@ID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Value = ID;
                    cmd.Parameters.Add(IDParam);

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            list.Policies = new List<DTO.PolicyListElement>();
                            while (reader.Read())
                            {
                                DTO.PolicyListElement element = new DTO.PolicyListElement();
                                element.ID = reader.GetGuid(0);
                                element.Name = reader.GetString(1);
                                if (reader.IsDBNull(2))
                                {
                                    element.Description = null;
                                }
                                else
                                {
                                    element.Description = reader.GetString(2);
                                }
                                list.Policies.Add(element);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }

            return list;

        }

        public static DTO.PolicyList ListPoliciesForAssertionTypeID(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            DTO.PolicyList list = new DTO.PolicyList();
            const string sprocname = "[ServiceEngine].[ListPoliciesForAssertionTypeID]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter IDParam = new SqlParameter("@ID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    IDParam.Value = ID;
                    cmd.Parameters.Add(IDParam);

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            list.Policies = new List<DTO.PolicyListElement>();
                            while (reader.Read())
                            {
                                DTO.PolicyListElement element = new DTO.PolicyListElement();
                                element.ID = reader.GetGuid(0);
                                element.Name = reader.GetString(1);
                                if (reader.IsDBNull(2))
                                {
                                    element.Description = null;
                                }
                                else
                                {
                                    element.Description = reader.GetString(2);
                                }
                                list.Policies.Add(element);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }

            return list;

        }

        public static void AssignPolicyAssertionToPolicy(Guid policyID, Guid policyAssertionID, int assertionOrder, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[AssignPolicyAssertionToPolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                //Note: No change tracking needed for newly activated operations at an endpoint
                //brokers will query for the operation to resolve since it won't be in the broker cache

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter PolicyIDParam = new SqlParameter("@PolicyID", SqlDbType.UniqueIdentifier);
                    SqlParameter PolicyAssertionIDParam = new SqlParameter("@PolicyAssertionID", SqlDbType.UniqueIdentifier);
                    SqlParameter AssertionOrderParam = new SqlParameter("@AssertionOrder", SqlDbType.SmallInt);


                    cmd.CommandType = CommandType.StoredProcedure;
                    PolicyIDParam.Value = policyID;
                    PolicyAssertionIDParam.Value = policyAssertionID;
                    AssertionOrderParam.Value = assertionOrder;

                    cmd.Parameters.Add(PolicyIDParam);
                    cmd.Parameters.Add(PolicyAssertionIDParam);
                    cmd.Parameters.Add(AssertionOrderParam);


                    cmd.ExecuteNonQuery();
                }

                if ((autoclose) && (txn != null)) txn.Commit();

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection in opened in this method
            }
        }

        public static void RemovePolicyAssertionFromPolicy(Guid policyID, Guid policyAssertionID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[RemovePolicyAssertionFromPolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                //Note: No change tracking needed for newly activated operations at an endpoint
                //brokers will query for the operation to resolve since it won't be in the broker cache

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter PolicyIDParam = new SqlParameter("@PolicyID", SqlDbType.UniqueIdentifier);
                    SqlParameter PolicyAssertionIDParam = new SqlParameter("@PolicyAssertionID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    PolicyIDParam.Value = policyID;
                    PolicyAssertionIDParam.Value = policyAssertionID;

                    cmd.Parameters.Add(PolicyIDParam);
                    cmd.Parameters.Add(PolicyAssertionIDParam);

                    cmd.ExecuteNonQuery();
                }

                if ((autoclose) && (txn != null)) txn.Commit();

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection in opened in this method
            }
        }

        public static void RemoveAllPolicyAssertionsFromPolicy(Guid policyID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[RemoveAllPolicyAssertionsFromPolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                //Note: No change tracking needed for newly activated operations at an endpoint
                //brokers will query for the operation to resolve since it won't be in the broker cache

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter PolicyIDParam = new SqlParameter("@PolicyID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    PolicyIDParam.Value = policyID;

                    cmd.Parameters.Add(PolicyIDParam);

                    cmd.ExecuteNonQuery();
                }

                if ((autoclose) && (txn != null)) txn.Commit();

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection in opened in this method
            }
        }

        #region Entity Policies functions
        //TODO these are obsolete. Need to remove them as part of the sprint.

        public static void AssignEntityPolicy(Guid entityID, Guid policyID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[AssignEntityPolicy]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter EntityIDParam = new SqlParameter("@EntityID", SqlDbType.UniqueIdentifier);
                    SqlParameter PolicyIDParam = new SqlParameter("@PolicyID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    EntityIDParam.Value = entityID;
                    cmd.Parameters.Add(EntityIDParam);
                    PolicyIDParam.Value = policyID;
                    cmd.Parameters.Add(PolicyIDParam);

                    cmd.ExecuteNonQuery();
                }

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }
        }

        public static void DeletePoliciesFromEntity(Guid entityID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            const string sprocname = "[ServiceEngine].[DeletePoliciesFromEntity]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    SqlParameter EntityIDParam = new SqlParameter("@EntityID", SqlDbType.UniqueIdentifier);

                    cmd.CommandType = CommandType.StoredProcedure;
                    EntityIDParam.Value = entityID;
                    cmd.Parameters.Add(EntityIDParam);

                    cmd.ExecuteNonQuery();
                }

            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }
        }

        public static DTO.Policy[] GetEntityPolicies(Guid entityID, SqlTransaction txn, SqlConnection conn)
        {
            bool autoclose = false;
            List<DTO.Policy> polList = null;
            DTO.Policy[] arrPol = null;
            const string sprocname = "[ServiceEngine].[GetEntityPolicies]";

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                using (SqlCommand cmd = new SqlCommand(sprocname, conn, txn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    SqlParameter EntityIDParam = new SqlParameter("@EntityID", SqlDbType.UniqueIdentifier);
                    EntityIDParam.Value = entityID;
                    cmd.Parameters.Add(EntityIDParam);

                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            polList = new List<DTO.Policy>();
                            while (reader.Read())
                            {
                                polList.Add(GetPolicy(reader.GetGuid(0), txn, conn));
                            }
                        }
                    }
                }

                if (polList != null)
                {
                    arrPol = new DTO.Policy[polList.Count];
                    for (int i = 0; i < polList.Count; i++)
                    {
                        arrPol[i] = polList[i];
                    }
                }
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close(); //Close connection if opened in this method
            }
            return arrPol;
        }

        #endregion
    }
}
